package io.spring.start.site.web;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import org.gitlab4j.api.models.Group;
import org.gitlab4j.api.models.Project;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.collect.Lists;

import cn.hutool.http.HttpStatus;
import io.spring.initializr.metadata.InitializrMetadata;
import io.spring.initializr.metadata.InitializrMetadataProvider;
import io.spring.initializr.web.project.InvalidProjectRequestException;
import io.spring.initializr.web.project.ProjectGenerationInvoker;
import io.spring.initializr.web.project.ProjectGenerationResult;
import io.spring.initializr.web.project.ProjectRequest;
import io.spring.initializr.web.project.WebProjectRequest;
import io.spring.start.site.config.GitlabProperties;
import io.spring.start.site.gitlab.GitlabService;
import io.spring.start.site.vo.GitlabVo;
import io.spring.start.site.vo.UploadFile;

@RestController
@RequestMapping("gitlab")
public class GitllabProjectResource<R extends ProjectRequest> {

	private InitializrMetadataProvider metadataProvider;

	private ProjectGenerationInvoker<R> projectGenerationInvoker;

	private GitlabService gitlabService;

	private GitlabProperties gitlabProperties;

	public GitllabProjectResource(InitializrMetadataProvider metadataProvider,
			ProjectGenerationInvoker<R> projectGenerationInvoker, GitlabService gitlabService,
			GitlabProperties gitlabProperties) {
		this.metadataProvider = metadataProvider;
		this.projectGenerationInvoker = projectGenerationInvoker;
		this.gitlabService = gitlabService;
		this.gitlabProperties = gitlabProperties;
	}

	@ModelAttribute
	ProjectRequest projectRequest(@RequestHeader Map<String, String> headers,
			@RequestParam(name = "style", required = false) String style) {
		if (style != null) {
			throw new InvalidProjectRequestException("Dependencies must be specified using 'dependencies'");
		}
		return projectRequest(headers);
	}

	public ProjectRequest projectRequest(Map<String, String> headers) {
		WebProjectRequest request = new WebProjectRequest();
		request.getParameters().putAll(headers);
		request.initialize(getMetadata());
		return request;
	}

	protected InitializrMetadata getMetadata() {
		return this.metadataProvider.get();
	}

	@RequestMapping(path = "import", method = { RequestMethod.GET, RequestMethod.POST })
	public ResponseEntity<String> importGitab(R request, @RequestBody GitlabVo gitlabVo) throws IOException {
		try {
			Group group = gitlabService.getGroup(gitlabVo.getTeamName());
			if (Objects.isNull(group)) {
				group = gitlabService.createGroup(gitlabVo.getTeamName());
			}
			boolean existProject = gitlabService.existProject(gitlabVo.getTeamName(), gitlabVo.getProjectName());
			if (existProject) {
				return ResponseEntity.status(HttpStatus.HTTP_NOT_EXTENDED).body("项目已存在，暂不能导入！");
			}
			Project project = gitlabService.createProject(gitlabVo, group);
			importProject2Git(request, project);
		}
		catch (Exception e) {
			return ResponseEntity.status(HttpStatus.HTTP_NOT_EXTENDED).body(e.getMessage());
		}
		return ResponseEntity.ok("导入项目成功!");
	}

	@RequestMapping(path = "meta", method = { RequestMethod.GET, RequestMethod.POST })
	public ResponseEntity<GitlabProperties> metaGitab() {
		GitlabProperties gp = new GitlabProperties();
		gp.setUrl(gitlabProperties.getUrl());
		gp.setPersonalAccessToken(gitlabProperties.getPersonalAccessToken());
		gp.setTeamName(gitlabProperties.getTeamName());
		return ResponseEntity.ok(gp);
	}

	/**
	 * 待导入文件的信息
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private void importProject2Git(R request, Project project) throws IOException {
		ProjectGenerationResult result = this.projectGenerationInvoker.invokeProjectStructureGeneration(request);
		List<UploadFile> uploadFiles = parseUploadFiles(result);
		gitlabService.addFile2Project(project, uploadFiles);
	}

	/**
	 * 解析待上传的文件信息
	 * @param result
	 * @return
	 * @throws IOException
	 */
	private List<UploadFile> parseUploadFiles(ProjectGenerationResult result) throws IOException {
		List<UploadFile> uploadFiles = Lists.newArrayList();
		Stream<Path> files = Files.walk(result.getRootDirectory());
		try (files) {
			files.filter((path) -> !result.getRootDirectory().equals(path)).forEach((path) -> {
				try {
					UploadFile uploadFile = new UploadFile();
					uploadFile.setRootDirectory(result.getRootDirectory());
					uploadFile.setPath(path);
					uploadFiles.add(uploadFile);
				}
				catch (Exception ex) {
					throw new IllegalStateException(ex);
				}
			});
		}
		return uploadFiles;
	}

}
